﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace WriteDeviceID
{
    public partial class frmMain : Form
    {
        const string _serverIP = "121.196.201.131";
        const string _localIP = "127.0.0.1";
        const int _serverPort = 7820;
        enum GETID{ Free,GetID,WaitID,WriteID};


        Socket socketLink = null;
        Thread _receiveThread = null;
        Thread _sendThread = null;
        GETID _getIDFlag = GETID.Free;//1发送申请指令时，2为等待服务器返回ID，3为向硬件写入ID写入成功后归零

        public frmMain()
        {
            InitializeComponent();
        }

        /// <summary>
        /// 将字符串转为Ascii 的十六进制
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        static public byte[] StringToAsciiByte(string str)
        {
            return System.Text.Encoding.ASCII.GetBytes(str);
        }

        /// <summary>
        /// 将Ascii的十六进制数组转化为字符串
        /// </summary>
        /// <param name="byteArray"></param>
        /// <returns></returns>
        static public string AsciiByteToString(byte[] byteArray)
        {
            return System.Text.Encoding.ASCII.GetString(byteArray);
        }

        private void btnLinkServer_Click(object sender, EventArgs e)
        {
            if (btnLinkServer.Text == "连接")
            {
                btnLinkServer.Text = "断开";
                LinkThread();
                btnWriteID.Enabled = true;
                cbTest.Enabled = false;
                cbProduction.Enabled = false;
            }
            else
            {
                timer1.Enabled = false;
                if(_sendThread != null)
                {
                    _sendThread.Abort();
                    _sendThread = null;
                }
                if(_receiveThread != null)
                {
                    _receiveThread.Abort();
                    _receiveThread = null;
                }
                if(socketLink != null)
                {
                    socketLink.Close();
                    socketLink = null;
                }
                
                btnLinkServer.Text = "连接";
                label2.Text = "连接断开！";
                btnWriteID.Enabled = false;
                cbTest.Enabled = true;
                cbProduction.Enabled = true;
            }
        }

        private void LinkThread()
        {
            string ipstr = _localIP;
            socketLink = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //将字符串地址转化为网际协议地址
            if (cbTest.Checked)
                ipstr = _localIP;
            else if (cbProduction.Checked)
                ipstr = _serverIP;
            else if (cbOther.Checked)
                ipstr = tbIP.Text.Trim();
            else
                MessageBox.Show("请选择 测试模式 或 生产模式 ！");
            IPAddress ipAddress = IPAddress.Parse(ipstr);
            //使用指定地址和端口号实例化新的网络端点
            IPEndPoint remoteEP = new IPEndPoint(ipAddress, _serverPort);
            try
            {
                socketLink.Connect(remoteEP);

                if (_receiveThread == null)
                {
                    _receiveThread = new Thread(ReceiveData);
                    _receiveThread.IsBackground = true;
                    _receiveThread.Start(socketLink);
                }
            }
            catch {
                MessageBox.Show("请确认服务器是否已正常运行！");
                btnLinkServer.PerformClick();
                //btnLinkServer.Text = "连接";
            }
        }

        private void SendData(byte[] buffer)
        {
            try
            {
                if(socketLink != null)
                    socketLink.Send(buffer);
            }
            catch { }
        }

        private void SendThread(object oLink)
        {
            Socket sLink = oLink as Socket;
            
            while (true)
            {
                int timerout = 0;
                do
                {
                    Thread.Sleep(50);
                    timerout++;
                    if (_getIDFlag == GETID.GetID) break;
                } while (timerout < 20);
                
                string cmd;
                if (_getIDFlag == GETID.GetID)
                {
                    cmd = "GETID\r\n";
                    _getIDFlag = GETID.WaitID;
                    byte[] sendByte = StringToAsciiByte(cmd);
                    SendData(sendByte);
                    Thread.Sleep(1000);
                }
                else
                {
                    cmd = "GetHeard\r\n";
                    byte[] sendByte = StringToAsciiByte(cmd);
                    SendData(sendByte);
                }
            }
        }

        private void ReceiveData(object oLink)
        {
            Socket sLink = oLink as Socket;
            byte[] receiveBuf = new byte[2048];

            if (_sendThread == null)
            {
                _sendThread = new Thread(SendThread);
                _sendThread.IsBackground = true;
                _sendThread.Start(oLink);
            }

            int recLenpw = sLink.Receive(receiveBuf);
            if (recLenpw == 0)
            {
                return;
            }
            DateTime dt = DateTime.Now;
            string timestr = "*++**++*=\r\n";//dt.ToString("yy-MM-dd");
            byte[] sendByte = StringToAsciiByte(timestr);
            sendByte[0] <<= 1;
            sendByte[3] <<= 1;
            sendByte[8] <<= 1;

            SendData(sendByte);


            while (true)
            {
                int recLen = sLink.Receive(receiveBuf);
                if (recLen == 0)
                {
                    this.Invoke(new EventHandler(delegate
                    {
                        btnLinkServer.PerformClick();
                    }));
                    break;//退出
                }
                byte[] rBuf = new byte[recLen];
                Array.Copy(receiveBuf, rBuf, recLen);
                string cmd = AsciiByteToString(rBuf);

                if(_getIDFlag == GETID.WaitID)
                {
                    if(cmd.Length == 9+16 + 2)
                    {
                        int startIndex = cmd.IndexOf('=')+1;
                        int lenght = cmd.IndexOf('\r') - startIndex;
                        string idStr = cmd.Substring(startIndex, lenght);
                        //写入ID
                        _getIDFlag = GETID.Free;
                        Debug.Print("ID="+ idStr);
                        this.Invoke(new EventHandler(delegate
                        {
                            tbDeviceID.Text = idStr;
                        }));
                    }
                }

                Debug.Print(cmd);

                this.Invoke(new EventHandler(delegate
                {
                    label2.Text = "连接在线...";
                }));
            }
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            
        }

        

        private void frmMain_Load(object sender, EventArgs e)
        {
            timer1.Enabled = false;
            timer1.Interval = 1000;
            timer1.Enabled = true;
        }

        private void btnWriteID_Click(object sender, EventArgs e)
        {
            _getIDFlag = GETID.GetID;
        }

        private void cbTest_CheckedChanged(object sender, EventArgs e)
        {
            if (cbTest.Checked)
            {
                cbProduction.Checked = false;
                cbOther.Checked = false;
            } 
        }

        private void cbProduction_CheckedChanged(object sender, EventArgs e)
        {
            if (cbProduction.Checked)
            {
                cbTest.Checked = false;
                cbOther.Checked = false;
            } 
        }

        private void cbOther_CheckedChanged(object sender, EventArgs e)
        {
            if (cbOther.Checked)
            {
                cbTest.Checked = false;
                cbProduction.Checked = false;
            }
        }
    }
}
